package com.tiancheng.trade.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiancheng.trade.commom.core.data.Result;
import com.tiancheng.trade.commom.core.enums.PaySceneEnum;
import com.tiancheng.trade.commom.core.enums.PaymentChannelEnum;
import com.tiancheng.trade.commom.core.enums.PaymentWayEnum;
import com.tiancheng.trade.commom.core.enums.VerificationStatusEnum;
import com.tiancheng.trade.commom.core.exception.Asserts;
import com.tiancheng.trade.commom.core.exception.BusinessException;
import com.tiancheng.trade.commom.core.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.commom.web.cache.AccessTokenCache;
import com.tiancheng.trade.commom.core.utils.JsonUtil;
import com.tiancheng.trade.commom.web.auth.StpCustomKit;
import com.tiancheng.trade.commom.core.data.ApplicationInfo;
import com.tiancheng.trade.commom.web.feign.MerchantFeignService;
import com.tiancheng.trade.commom.web.model.OrgBusinessDTO;
import com.tiancheng.trade.commom.web.model.SubjectProfile;
import com.tiancheng.trade.commom.web.model.request.*;
import com.tiancheng.trade.commom.web.model.response.PaymentPayWayQueryResponse;
import com.tiancheng.trade.commom.web.model.response.QueryOrderMerchantResVO;
import com.tiancheng.trade.commom.web.model.response.UnifiedOrderResVO;
import com.tiancheng.trade.commom.web.model.response.VerificationOrderResponseVO;
import com.tiancheng.trade.order.bo.*;
import com.tiancheng.trade.order.bo.notify.PayResultOrderBO;
import com.tiancheng.trade.order.bo.notify.PayResultSubOrderBO;
import com.tiancheng.trade.order.convert.OrderConvert;
import com.tiancheng.trade.order.convert.SubOrderConvert;
import com.tiancheng.trade.order.enums.*;
import com.tiancheng.trade.order.mapper.SubOrderMapper;
import com.tiancheng.trade.order.model.*;
import com.tiancheng.trade.order.service.*;
import com.tiancheng.trade.order.util.EnumUtil;
import com.tiancheng.trade.order.util.ObjectConvertUtil;
import com.tiancheng.trade.order.util.cache.OrderCache;
import com.tiancheng.trade.order.mq.MessageProducer;
import com.tiancheng.trade.order.util.lock.Lock;
import com.tiancheng.trade.order.vo.api.VerificationOrderVO;
import com.tiancheng.trade.order.vo.open.order.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @ClassName OpenOrderServiceImpl
 * @Description TODO
 * @Author kellen
 * @Date 2024/11/24 16:41
 */
@Slf4j
@Service
public class OpenOrderServiceImpl extends BaseOrderPayService implements OpenOrderService {
    @Resource
    private CouponService couponService;
    @Resource
    private CreditOrderService creditOrderService;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private MerchantFeignService merchantFeignService;
    @Resource
    private OrderBatchService orderBatchService;
    @Resource
    private SubOrderMapper subOrderMapper;
    @Resource
    private RefundOrdersService refundOrdersService;
    @Resource
    private BillService billService;
    @Resource
    private MessageProducer messageProducer;


    @Override
    public ApplicationInfo getApplicationInfo(String termNo) {
        Object extra = StpCustomKit.OPEN.getExtra("application");
        if (Objects.nonNull(extra)) {
            List<ApplicationInfo> apps = new ArrayList<>();
            SubjectProfile subjectProfile = JsonUtil.fromJson(JsonUtil.toJsonString(extra), SubjectProfile.class);
            String clientId = MapUtils.getString(subjectProfile.getAttributes(), "clientId");
            Integer expiresIn = MapUtils.getInteger(subjectProfile.getAttributes(), "expiresIn");

            Optional<List<ApplicationInfo>> optional = AccessTokenCache.getOrderApplication(clientId);
            if (optional.isPresent()) {
                apps = optional.get();
            } else {
                // 查询机构业务配置
                QueryOrgBusinessReq businessReq = new QueryOrgBusinessReq();
                businessReq.setClientId(clientId);
                businessReq.setTermNo(termNo);
                Result<List<OrgBusinessDTO>> result = merchantFeignService.queryOrgBusiness(businessReq);
                BusinessErrorInfoEnum.ORDER_CREATE_APPLICATION_ERROR.assertIsTrue(result.getRet() == 0 && Objects.nonNull(result.getData()));
                for (OrgBusinessDTO datum : result.getData()) {
                    // 查询机构支付通道配置
                    ApplicationInfo applicationInfo = new ApplicationInfo();
                    applicationInfo.setId(subjectProfile.getId());
                    applicationInfo.setClientId(clientId);
                    applicationInfo.setClientSecret(MapUtils.getString(subjectProfile.getAttributes(), "clientSecret"));
                    applicationInfo.setName(MapUtils.getString(subjectProfile.getAttributes(), "name"));
                    applicationInfo.setIdPre(datum.getIdPre());
                    applicationInfo.setTermNo(datum.getTermNo());
                    applicationInfo.setBusinessCode(datum.getBusinessCode());
                    applicationInfo.setBusinessName(datum.getBusinessName());
                    applicationInfo.setOrganizationCode(datum.getOrganizationCode());
                    applicationInfo.setOrganizationName(datum.getOrganizationName());
                    applicationInfo.setOrgPaymentChannelId(datum.getOrgPaymentChannelId());
                    applicationInfo.setPaymentChannelCode(datum.getPaymentChannelCode());
                    apps.add(applicationInfo);
                }
                AccessTokenCache.cacheOrderApplication(clientId, apps, expiresIn);
            }

            Asserts.isTrue(CollectionUtils.isNotEmpty(apps),"未查询到支付商户配置！");
            if(StringUtils.isNotEmpty(termNo)){
                return apps.stream().filter(a->a.getTermNo().equals(termNo)).findFirst().get();
            }
            // 查询
            return apps.get(0);
        }
        return null;
    }

    @Override
    public OpenCreateOrderResVO create(OrderBO orderBO, List<SubOrderBO> subOrderBOS, List<CouponBO> couponBOS) throws BusinessException {
        // 订单号码、订单重复校验
        ApplicationInfo applicationInfo = this.orderIdCheck(orderBO, subOrderBOS);
        // 如果是续费订单、尾款订单，验证关联的上一笔订单有效性
        OrderTypeEnum orderTypeEnum = EnumUtil.getEnumByCode(OrderTypeEnum.class, orderBO.getOrderType());
        if (orderTypeEnum == OrderTypeEnum.renew || orderTypeEnum == OrderTypeEnum.balance) {
            QueryWrapper<Order> originalConditions = new QueryWrapper<>();
            originalConditions.eq("order_id", orderBO.getOriginalOrderId());
            originalConditions.eq("order_status", OrderStatusEnum.paid.getCode());
            Long count = orderMapper.selectCount(originalConditions);
            BusinessErrorInfoEnum.ORDER_CREATE_ORIGINAL.assertIsTrue(count > 0);
        }
        // 保存主订单
        Order order = ObjectConvertUtil.convert(orderBO, Order.class).get();
        order.setOrgPaymentChannelId(applicationInfo.getOrgPaymentChannelId());
        order.setClientId(applicationInfo.getClientId());
        order.setOrganizationCode(applicationInfo.getOrganizationCode());
        order.setBusinessCode(applicationInfo.getBusinessCode());
        order.setPayChannel(applicationInfo.getPaymentChannelCode());

        order.setOrderStatus(OrderStatusEnum.waiting_pay.getCode());
        order.setPayStatus(OrderPayStatusEnum.un_pay.getCode());
        order.setSubOrderCnt(subOrderBOS.size());
        order.setCreatedDt(LocalDateTime.now());
        order.setBatchId(orderBO.getBatchId());
        order.setRefundTimes(0);        //初始退款次数为0
        // 支付过期时间，下单时间20分钟后
        if (order.getPayExpiryTime() == null) {
            order.setPayExpiryTime(order.getCreatedDt().plusMinutes(30));
        }
        // 计算主订单的优惠金额、实际支付金额
        int discountTotal = 0;//主订单优惠券金额
        if (couponBOS.size() > 0) {
            discountTotal = couponBOS.stream().mapToInt(CouponBO::getDiscount).sum();
            order.setDiscount(discountTotal);//优惠总金额，初始设为平台优惠金额
            order.setPlatformDiscount(discountTotal);//平台优惠金额
            order.setPayAmount(order.getOrderAmount() - order.getPlatformDiscount());//订单支付总金额=订单应收金额-平台优惠总金额
        } else {
            order.setPayAmount(order.getOrderAmount());
        }

        // 保存子订单
        // 计算出子订单的优惠金额（目前只支持平台单张优惠，分摊到各个子订单）
        if (couponBOS.size() > 0) {
            for (int i = 0; i < subOrderBOS.size(); i++) {
                SubOrderBO subOrderBO = subOrderBOS.get(i);
                if (i == subOrderBOS.size() - 1) {
                    subOrderBO.setDiscount(discountTotal - subOrderBOS.stream().mapToInt(SubOrderBO::getDiscount).sum());
                    subOrderBO.setPlatformDiscount(discountTotal - subOrderBOS.stream().mapToInt(SubOrderBO::getPlatformDiscount).sum());
                } else {
                    // 1、计算子订单所占总金额的比例，小数点后取10位，然后截取
                    // 2、总优惠金额*子订单比例，然后四舍五入取整
                    int divide = BigDecimal.valueOf(subOrderBO.getSubOrderAmount()).divide(BigDecimal.valueOf(order.getOrderAmount()), 10, RoundingMode.DOWN).multiply(BigDecimal.valueOf(discountTotal)).setScale(0, RoundingMode.HALF_UP).intValue();
                    subOrderBO.setDiscount(divide);
                    subOrderBO.setPlatformDiscount(divide);
                }
                subOrderBO.setIsCoupon(subOrderBO.getDiscount() > 0 ? 1 : 0);
            }
        }
        AtomicReference<OpenCreateOrderResVO> result = new AtomicReference<>();
        transactionTemplate.execute(transactionStatus -> {
            try {
                int num = orderMapper.insert(order);
                final List<SubOrder> subOrders = subOrderService.create(subOrderBOS);
                // 保存优惠券
                if (couponBOS.size() > 0) {
                    couponService.create(couponBOS);
                }
                // 免押订单
                if (!StringUtils.isEmpty(orderBO.getSettlementInfo())) {
                    creditOrderService.create(orderBO, subOrderBOS);
                }
                final OpenCreateOrderResVO openCreateOrderResVO = OrderConvert.INSTANCE.getOpenCreateOrderResVO(order);
                openCreateOrderResVO.setSubOrders(OrderConvert.INSTANCE.getOpenCreateSubOrderResVOs(subOrders));
                result.set(openCreateOrderResVO);
                return true;
            } catch (Exception e) {
                transactionStatus.setRollbackOnly();
                throw e;
            }
        });
        return result.get();
    }

    @Override
    public int cancelOrder(OpenCancelOrderVO cancelOrderVO) {
        QueryWrapper<Order> conditions = new QueryWrapper<>();
        conditions.eq("order_id", cancelOrderVO.getOrderId());
        Order order = orderMapper.selectOne(conditions);
        BusinessErrorInfoEnum.ORDER_CLOSE_NO_DATA.assertNotNull(order);
        if (OrderStatusEnum.cancelled.getCode().equals(order.getOrderStatus())) {
            return 0;
        }
        if (order.getPayStatus().equals(OrderPayStatusEnum.paid.getCode())) {
            //判断，如果是已支付状态，往业务系统发送一次
            PayResultOrderBO payResultOrderBO = getPayResultOrderBO(order);
            payResultOrderBO.setClientId(order.getClientId());
            messageProducer.payResult(payResultOrderBO);
            return 1;
        }
        BusinessErrorInfoEnum.ORDER_CLOSE_STATUS_ERROR.assertIsTrue(OrderStatusEnum.waiting_pay.getCode().equals(order.getOrderStatus()));

        if (StringUtils.isEmpty(order.getOrderId())) {
            order.setOrderId(cancelOrderVO.getOrderId());
        }
        final boolean[] isSc = {false};
        transactionTemplate.execute(transactionStatus -> {
            try {
                // 关闭相应的流水
                isSc[0] = this.closeTradeFlow(order);
                if (isSc[0]) {
                    // 关闭流水成功，解锁优惠券
                    couponService.unlock(order.getUid(), new String[]{cancelOrderVO.getOrderId()}, null);

                    Order updateOrder = new Order();
                    updateOrder.setOrderStatus(OrderStatusEnum.cancelled.getCode());
                    orderMapper.update(updateOrder, conditions);

                    final SubOrder updateSubOrder = new SubOrder();
                    updateSubOrder.setSubOrderStatus(OrderStatusEnum.cancelled.getCode());
                    subOrderMapper.update(updateSubOrder, new LambdaQueryWrapper<SubOrder>().eq(SubOrder::getOrderId, cancelOrderVO.getOrderId()));
                }
                if (!StringUtils.isEmpty(order.getBatchId())) {
                    // 关闭批次订单
                    orderBatchService.close(order.getUid(), order.getBatchId());
                }
                return true;
            } catch (Exception e) {
                transactionStatus.setRollbackOnly();
                throw e;
            }
        });
        return isSc[0] ? 0 : 2;
    }

    @Override
    public OpenQueryOrderInfoResVo queryOrderInfo(OpenQueryOrderInfoReqVO openQueryOrderInfoReqVO) {
        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderId, openQueryOrderInfoReqVO.getOrderId()));
        if(null==order){
            return null;
        }
        final OpenQueryOrderInfoResVo openQueryOrderInfoResVo = OrderConvert.INSTANCE.order2OpenQueryOrderInfoResVo(order);
        openQueryOrderInfoResVo.setPayLeftSecond(Duration.between(LocalDateTime.now(), order.getPayExpiryTime()).toMillis() / 1000);

        // 子订单信息
        final List<SubOrder> subOrders = subOrderMapper.selectList(new LambdaQueryWrapper<SubOrder>().eq(SubOrder::getOrderId, openQueryOrderInfoReqVO.getOrderId()));
        openQueryOrderInfoResVo.setSubOrders(SubOrderConvert.INSTANCE.subOrders2OpenQueryOrderInfoResSubOrderVos(subOrders));
        return openQueryOrderInfoResVo;
    }

    @Override
    public OpenCashierResVO cashier(OpenCashierVO cashierVO) {
        QueryWrapper<Order> conditions = new QueryWrapper<>();
        //conditions.eq("uid", cashierVO.getUid());
        conditions.eq("order_id", cashierVO.getOrderId());
        conditions.eq("order_status", OrderStatusEnum.waiting_pay.getCode());
        List<Order> orders = orderMapper.selectList(conditions);
        BusinessErrorInfoEnum.ORDER_CASHIER_STATUS.assertIsTrue(orders.size() == new ArrayList<String>() {{
            add(cashierVO.getOrderId());
        }}.size());

        // 获取订单的支付渠道，并判断禁止跨渠道支付，以及判断订单是否支付超时
        Long orgPaymentChannelId = orders.get(0).getOrgPaymentChannelId();
        for (Order order : orders) {
            BusinessErrorInfoEnum.ORDER_CASHIER_CHANNEL_DIFF.assertIsTrue(orgPaymentChannelId.equals(order.getOrgPaymentChannelId()));
            BusinessErrorInfoEnum.ORDER_PAY_TIMEOUT_CLOSE.assertIsTrue(order.getPayExpiryTime().isAfter(LocalDateTime.now()));
            BusinessErrorInfoEnum.ORDER_PAY_NOT_ALLOW_ORDER_TYPE_ERROR.assertIsTrue(StringUtils.isEmpty(order.getBatchId()));
        }

        // 判断优惠券，目前只允许带一张优惠券支付，如果是合单支付，不允许带优惠券
        List<Coupon> coupons = couponService.find(new String[]{cashierVO.getOrderId()});
        OpenCashierResVO cashierResVO = new OpenCashierResVO();
        cashierResVO.setOrderSource(orders.size() > 1 ? OrderSourceEnum.CONSOLIDATION.getCode() : orders.get(0).getOrderSource());
        cashierResVO.setType(EnumUtil.getEnumByCode(OrderSourceEnum.class, cashierResVO.getOrderSource()).name().toLowerCase());
        cashierResVO.setOrderName(orders.get(0).getOrderName());
        final Set<String> batchIds = orders.stream().filter(o -> !StringUtils.isEmpty(o.getBatchId())).map(Order::getBatchId).collect(Collectors.toSet());
        if (CollectionUtils.isNotEmpty(batchIds) && batchIds.size() > 1) {
            // 有多个批次id，或者不带批次号的订单与带批次号的订单同时支付
            BusinessErrorInfoEnum.ORDER_PAY_NOT_ALLOW_MERGE_ERROR.assertFail();
        }

        if (CollectionUtils.isNotEmpty(batchIds) && batchIds.size() == 1) {
            // 只有一个批次号
            OrderBatch orderBatch = orderBatchService.findByBatchId(orders.get(0).getBatchId());
            cashierResVO.setOrderName(orderBatch.getOrderName());
        }

        cashierResVO.setPayChannel(orders.get(0).getPayChannel());
        LocalDateTime payExpiryTime = orders.stream().map(Order::getPayExpiryTime).min(Comparator.comparing(date -> date.toEpochSecond(ZoneOffset.of("+8")))).get();
        cashierResVO.setPayLeftTime(payExpiryTime.toEpochSecond(ZoneOffset.of("+8")) - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
        long discount = coupons.stream().mapToInt(Coupon::getDiscount).sum();
        cashierResVO.setDiscount(new BigDecimal(discount).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
        long payAmount = orders.stream().mapToInt(Order::getPayAmount).sum();
        cashierResVO.setPayAmount(new BigDecimal(payAmount).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
        long orderAmount = orders.stream().mapToInt(Order::getOrderAmount).sum();
        cashierResVO.setOrderAmount(new BigDecimal(orderAmount).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
        orders.forEach(order -> cashierResVO.getOrders().add(new OpenCashierResVO.Order(order.getOrderId(), order.getOrderName(), new BigDecimal(order.getOrderAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP), new BigDecimal(order.getPayAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP))));

        // 到支付中心根据支付渠道获取支付方式
        final List<PaymentPayWayQueryResponse> channels = this.getPayWayListByPayChannel(orders.get(0).getOrgPaymentChannelId(),
                orders.get(0).getPayChannel(), cashierVO.getPayScene(), cashierVO.getPayWay());
        cashierResVO.setPaymentWays(channels);
        long platformDiscount = orders.stream().mapToInt(Order::getPlatformDiscount).sum();
        cashierResVO.setNotPay(0);
        if (platformDiscount == orderAmount && payAmount == 0) {
            // 优惠全额抵扣了，不需要支付
            // 直接调用支付接口
            final OpenOrderPayVO payVO = new OpenOrderPayVO();
            payVO.setUid(cashierVO.getUid());
            payVO.setPayWay(PaymentWayEnum.WECHAT.getCode());
            payVO.setPayScene(PaySceneEnum.APP.getCode());
            payVO.setOrderId(orders.stream().map(Order::getOrderId).collect(Collectors.toList()).get(0));
            this.pay(payVO);
            cashierResVO.setNotPay(1);
        }
        return cashierResVO;
    }

    @Override
    public OpenInitCashierResVO initCashier(OpenInitCashierVO cashierVO) {
        Asserts.isTrue(cashierVO.getPayScene().equals(PaySceneEnum.PCWEB.getCode())
                || cashierVO.getPayScene().equals(PaySceneEnum.H5.getCode()), "收银台暂不支持其他的支付场景！");
        QueryWrapper<Order> conditions = new QueryWrapper<>();
        conditions.eq("order_id", cashierVO.getOrderId());
        conditions.eq("order_status", OrderStatusEnum.waiting_pay.getCode());
        List<Order> orders = orderMapper.selectList(conditions);
        BusinessErrorInfoEnum.ORDER_CASHIER_STATUS.assertIsTrue(orders.size() == new ArrayList<String>() {{
            add(cashierVO.getOrderId());
        }}.size());

        // 获取订单的支付渠道，并判断禁止跨渠道支付，以及判断订单是否支付超时
        Long paymentChannelId = orders.get(0).getOrgPaymentChannelId();
        for (Order order : orders) {
            BusinessErrorInfoEnum.ORDER_CASHIER_CHANNEL_DIFF.assertIsTrue(paymentChannelId.equals(order.getOrgPaymentChannelId()));
            BusinessErrorInfoEnum.ORDER_PAY_TIMEOUT_CLOSE.assertIsTrue(order.getPayExpiryTime().isAfter(LocalDateTime.now()));
            BusinessErrorInfoEnum.ORDER_PAY_NOT_ALLOW_ORDER_TYPE_ERROR.assertIsTrue(StringUtils.isEmpty(order.getBatchId()));
        }
        OpenInitCashierResVO cashierResVO = new OpenInitCashierResVO();
        cashierResVO.setOrderName(orders.get(0).getOrderName());
        final Set<String> batchIds = orders.stream().filter(o -> !StringUtils.isEmpty(o.getBatchId())).map(Order::getBatchId).collect(Collectors.toSet());
        if (CollectionUtils.isNotEmpty(batchIds) && batchIds.size() > 1) {
            // 有多个批次id，或者不带批次号的订单与带批次号的订单同时支付
            BusinessErrorInfoEnum.ORDER_PAY_NOT_ALLOW_MERGE_ERROR.assertFail();
        }
        if (CollectionUtils.isNotEmpty(batchIds) && batchIds.size() == 1) {
            // 只有一个批次号
            OrderBatch orderBatch = orderBatchService.findByBatchId(orders.get(0).getBatchId());
            cashierResVO.setOrderName(orderBatch.getOrderName());
        }
        cashierResVO.setPayChannel(orders.get(0).getPayChannel());
        LocalDateTime payExpiryTime = orders.stream().map(Order::getPayExpiryTime).min(Comparator.comparing(date -> date.toEpochSecond(ZoneOffset.of("+8")))).get();
        cashierResVO.setPayLeftTime(payExpiryTime.toEpochSecond(ZoneOffset.of("+8")) - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));

        long payAmount = orders.stream().mapToInt(Order::getPayAmount).sum();
        cashierResVO.setPayAmount(new BigDecimal(payAmount).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
        long orderAmount = orders.stream().mapToInt(Order::getOrderAmount).sum();
        cashierResVO.setOrderAmount(new BigDecimal(orderAmount).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
        long discountAmount = orders.stream().mapToInt(Order::getDiscount).sum();
        cashierResVO.setDiscount(new BigDecimal(discountAmount).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
        // 到支付中心根据支付渠道获取支付方式
        final List<PaymentPayWayQueryResponse> channels = this.getPayWayListByPayChannel(orders.get(0).getOrgPaymentChannelId(),
                orders.get(0).getPayChannel(), cashierVO.getPayScene(), cashierVO.getPayWay());
        Asserts.isTrue(CollectionUtils.isNotEmpty(channels), "当前支付场景暂无支持的支付方式！");

        cashierResVO.setPayWayList(channels);
        String jumpUrl = orderCenterConfigProperties.getCashRegisterUrl();// 交易中台的收银台地址
        StringBuilder sb = new StringBuilder(jumpUrl);
        sb.append("?orderId=").append(cashierVO.getOrderId()).append("&payScene=").append(cashierVO.getPayScene());
        // 支付方式
        if (StringUtils.isNotEmpty(cashierVO.getPayWay())) {
            sb.append("&payWay=").append(cashierVO.getPayWay());
        }
        // 回调地址
        String callbackUrl = StringUtils.isNotEmpty(cashierVO.getCallbackUrl()) ? URLEncoder.encode(cashierVO.getCallbackUrl(), StandardCharsets.UTF_8) : "";
        sb.append("&callbackUrl=").append(callbackUrl);
        sb.append("&token=").append(StpCustomKit.OPEN.getTokenValue());
        cashierResVO.setPayUrl(sb.toString());
        return cashierResVO;
    }

    @Override
    public OpenOrderPrePayResVO pay(OpenOrderPayVO orderPayVO) throws BusinessException {
        // 校验支付通道&支付场景
        final Optional<PaymentWayEnum> paymentWayEnum = PaymentWayEnum.getByCode(orderPayVO.getPayWay());
        BusinessErrorInfoEnum.ORDER_PAY_OTHER_ERROR.assertIsTrue(paymentWayEnum.isPresent(), "不支持的支付方式！");
        BusinessErrorInfoEnum.ORDER_PAY_OTHER_ERROR.assertIsTrue(PaySceneEnum.getByCode(orderPayVO.getPayScene()).isPresent(), "不支持的支付场景！");

        QueryWrapper<Order> conditions = new QueryWrapper<>();
        //conditions.eq("uid", uid);
        conditions.eq("order_id", orderPayVO.getOrderId());
        conditions.eq("order_status", OrderStatusEnum.waiting_pay.getCode());
        conditions.eq("pay_status", OrderPayStatusEnum.un_pay.getCode());
        List<Order> orders = orderMapper.selectList(conditions);
        // 检查订单状态、订单支付失效时间、订单禁止跨渠道支付
        BusinessErrorInfoEnum.ORDER_PAY_STATUS.assertIsTrue(orders.size() == 1);
        //BusinessErrorInfoEnum.ORDER_PAY_USER_ERROR.assertEquals(orders.get(0).getUid(),uid);
        String payChannel = orders.get(0).getPayChannel();
        String uid = orderPayVO.getUid();
        if (StringUtils.isEmpty(uid) || uid.equals("0")) {
            uid = orders.get(0).getUid();
        }
        if (!StringUtils.isEmpty(uid) && !uid.equals(orders.get(0).getUid())) {
            log.warn("创建订单与支付不是同一个人，创建订单：{},支付：{}", orders.get(0).getUid(), uid);
        }
        for (Order order : orders) {
            BusinessErrorInfoEnum.ORDER_PAY_NOT_ALLOW_ORDER_TYPE_ERROR.assertIsTrue(!OrderTypeEnum.deduction.getCode().equalsIgnoreCase(order.getOrderType()));
            BusinessErrorInfoEnum.ORDER_PAY_CHANNEL.assertIsTrue(payChannel.equals(order.getPayChannel()));
            BusinessErrorInfoEnum.ORDER_PAY_TIMEOUT_CLOSE.assertIsTrue(order.getPayExpiryTime().isAfter(LocalDateTime.now()));
            BusinessErrorInfoEnum.ORDER_PAY_NOT_ALLOW_ORDER_TYPE_ERROR.assertIsTrue(StringUtils.isEmpty(order.getBatchId()));
        }

        // 组织返回的支付信息
        OpenOrderPrePayResVO prePayResVO = new OpenOrderPrePayResVO();
        prePayResVO.setPayWay(orderPayVO.getPayWay());
        prePayResVO.setOpenid(orderPayVO.getOpenid());
        prePayResVO.setOrderName(orders.get(0).getOrderName());
        prePayResVO.setPayChannel(orders.get(0).getPayChannel());

        LocalDateTime payExpiryTime = orders.stream().map(Order::getPayExpiryTime).min(Comparator.comparing(date -> date.toEpochSecond(ZoneOffset.of("+8")))).get();
        prePayResVO.setPayLeftTime(payExpiryTime.toEpochSecond(ZoneOffset.of("+8")) - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
        long discount = orders.stream().mapToInt(Order::getPlatformDiscount).sum();//平台优惠金额
        prePayResVO.setDiscount(new BigDecimal(discount).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
        long payAmount = orders.stream().mapToInt(Order::getPayAmount).sum();
        prePayResVO.setPayAmount(new BigDecimal(payAmount).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
        long orderAmount = orders.stream().mapToInt(Order::getOrderAmount).sum();
        prePayResVO.setOrderAmount(new BigDecimal(orderAmount).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));

        List<OpenOrderPrePayResVO.Order> resOrders = orders.stream().map(order -> new OpenOrderPrePayResVO.Order(order.getOrderId(), order.getOrderName(), new BigDecimal(order.getOrderAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP), new BigDecimal(order.getPayAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP), EnumUtil.getEnumByCode(OrderSourceEnum.class, order.getOrderSource()).name().toLowerCase())).collect(Collectors.toList());
        prePayResVO.setOrders(resOrders);

        // 针对该用户加锁，5秒后自动释放，并发等待5秒获取，5秒后未获取抛出超时异常
        try (Lock lock = new Lock(Lock.LOCK_ORDER_PAY, orders.get(0).getUid(), 5, 5)) {
            BusinessErrorInfoEnum.ORDER_PAY_TIMEOUT.assertIsTrue(lock.getLockRes());

            // 判断并返回缓存中的预支付信息,缓存时长为半小时
            Optional<String> prePayInfo = this.getCachePrePayInfo(orders.get(0).getUid(), orderPayVO, orders, null);
            if (prePayInfo.isPresent()) {
                // 判断是否为银联+支付宝+app支付，需要重新生成一笔支付流水,坑爹
                if (orders.get(0).getPayChannel().equalsIgnoreCase(PaymentChannelEnum.UMS.getCode()) && orderPayVO.getPayScene().equalsIgnoreCase(PaySceneEnum.APP.getCode()) && orderPayVO.getPayWay().equalsIgnoreCase(PaymentWayEnum.ALIPAY.getCode())) {
                    log.info("作废支付宝缓存预支付信息，重新生成流水");
                    // TODO 调用支付中心查询该流水的支付结果，已支付则抛出异常
                    String cacheUniqueKey = orderIdHelper.getUniqueIdByOrderIds(orders.get(0).getUid(), orders.stream().map(Order::getOrderId).collect(Collectors.toList()), orderPayVO.getPayWay(), orderPayVO.getPayScene(), null);
                    OrderCache.delPrePayInfo(cacheUniqueKey);

                } else {
                    if (discount == orderAmount && payAmount == 0) {
                        // 优惠全额抵扣了，不需要支付
                        prePayResVO.setPayInfo("not_pay");
                    } else {
                        // 正常支付订单，需要支付
                        prePayResVO.setPayInfo(prePayInfo.get());
                    }
                    return prePayResVO;
                }
            }

            // 查询订单的优惠券信息
            List<Coupon> coupons = couponService.find(new String[]{orderPayVO.getOrderId()});
            String spInfo = coupons.stream().map(coupon -> coupon.getCouponCode() + "," + coupon.getCouponName()).collect(Collectors.toList()).stream().collect(Collectors.joining(","));

            String orderSource = orders.size() > 1 ? OrderSourceEnum.CONSOLIDATION.getCode() : orders.get(0).getOrderSource();
            String paymentId = orderIdHelper.getPaymentId(uid);
            OrderPayDTO orderPayDTO = new OrderPayDTO();
            orderPayDTO.setUid(uid);
            orderPayDTO.setOrderName(orders.get(0).getOrderName());
            orderPayDTO.setUserTel(orders.get(0).getMobile());
            orderPayDTO.setPaymentId(paymentId);
            orderPayDTO.setBusinessType(orderSource);
            orderPayDTO.setTs(LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
            orderPayDTO.setAmount(orders.stream().mapToInt(Order::getPayAmount).sum());
            orderPayDTO.setOrderAmount(orders.stream().mapToInt(Order::getOrderAmount).sum());
            orderPayDTO.setDiscount(orders.stream().mapToInt(Order::getPlatformDiscount).sum());
            orderPayDTO.setPayScene(orderPayVO.getPayScene());
            orderPayDTO.setPayChannel(payChannel);
            orderPayDTO.setPayWay(orderPayVO.getPayWay());
            orderPayDTO.setSpInfo(spInfo);
            orderPayDTO.setOpenid(orderPayVO.getOpenid());
            orderPayDTO.setSubAppId(orderPayVO.getSubAppId());
            orderPayDTO.setReturnUrl(orderPayVO.getReturnUrl());
            orderPayDTO.setPayExpiryTime(orders.get(0).getPayExpiryTime());

            // 如果是小程序支付，没有传openid，默认使用创建订单时的openid
            if (OrderSceneEnum.miniapp.name().equals(orderPayVO.getPayScene()) && StringUtils.isEmpty(orderPayVO.getOpenid())) {
                orderPayDTO.setOpenid(orders.get(0).getOpenid());
            }
            // 如果支付方式是微信，判断是否有goods_tag
            if (PaymentWayEnum.WECHAT.getCode().equals(orderPayVO.getPayWay()) && !StringUtils.isEmpty(orders.get(0).getGoodsTag())) {
                orderPayDTO.setGoodsTag(orders.get(0).getGoodsTag());
            }
            // 设置主商户
            orderPayDTO.setMerchantCode(orderCenterConfigProperties.getMainMerchant().getCode());
            orderPayDTO.setMerchantName(orderCenterConfigProperties.getMainMerchant().getName());
            orderPayDTO.setOrgPaymentChannelId(orders.get(0).getOrgPaymentChannelId());
            orderPayDTO.setClientId(orders.get(0).getClientId());
            orderPayDTO.setBusinessCode(orders.get(0).getBusinessCode());
            orderPayDTO.setOrganizationCode(orders.get(0).getOrganizationCode());
            // 组织子订单数据
            List<SubOrder> subOrders = subOrderService.find(new String[]{orderPayVO.getOrderId()});
            List<OrderPayDTO.SubOrderPayDTO> subOrderPayDTOS = subOrders.stream().map(subOrder -> {
                OrderPayDTO.SubOrderPayDTO subOrderPayDTO = ObjectConvertUtil.convert(subOrder, OrderPayDTO.SubOrderPayDTO.class).get();
                subOrderPayDTO.setOrderAmount(subOrder.getSubOrderAmount());
                subOrderPayDTO.setAmount(subOrder.getPayAmount());
                return subOrderPayDTO;
            }).collect(Collectors.toList());
            orderPayDTO.setSubOrderPayDTOS(subOrderPayDTOS);

            // 调用支付中心服务
            Result<UnifiedOrderResVO> result;
            if (discount == orderAmount && payAmount == 0 && CollectionUtils.isNotEmpty(coupons)) {
                // 优惠全额抵扣了，不需要支付
                orderPayDTO.setDiscount(0);
                orderPayDTO.setPayWay(PaymentWayEnum.DEDUCTION.getCode());
                orderPayDTO.setPayScene(PaySceneEnum.DEDUCTION.getCode());
                result = paymentFeignService.deductionUnified(orderPayDTO);
            } else {
                // 正常支付订单，需要支付
                result = paymentFeignService.unifiedOrder(orderPayDTO);
            }

            log.info("支付单号:{},支付返回信息:{}", paymentId, result);
            BusinessErrorInfoEnum.ORDER_PAY_SERVER_ERROR.assertIsTrue(result.getRet() == 0 && result.getErrorCode() == 0, StringUtils.isNotEmpty(result.getMsg()) ? result.getMsg() : "");

            // 缓存预支付信息
            UnifiedOrderResVO unifiedOrderResVO = result.getData();
//            TreeSet<String> orderIds = Stream.of(orderPayVO.getOrderIds()).collect(Collectors.toCollection(TreeSet::new));
            String cacheUniqueKey = orderIdHelper.getUniqueIdByOrderIds(orders.get(0).getUid(), orders.stream().map(Order::getOrderId).collect(Collectors.toList()), orderPayVO.getPayWay(), orderPayVO.getPayScene(), null);
            log.info("支付订单，获取cacheUniqueKey：{}", cacheUniqueKey);
            OrderCache.prePayInfo(cacheUniqueKey, unifiedOrderResVO);
            // 缓存提交的支付参数
            PayParamsCacheBO payParamsCacheBO = ObjectConvertUtil.convert(orderPayVO, PayParamsCacheBO.class).get();
            payParamsCacheBO.setOrderIds(new String[]{orderPayVO.getOrderId()});
            payParamsCacheBO.setUid(orders.get(0).getUid());
            OrderCache.payParams(paymentId, payParamsCacheBO);

            List<Order> collect = orders.stream().filter(o -> StringUtils.isEmpty(o.getOrderChannel())).collect(Collectors.toList());
            if (discount == orderAmount && payAmount == 0 && CollectionUtils.isNotEmpty(coupons)) {
                // 优惠全额抵扣了，不需要支付
                prePayResVO.setPayInfo("not_pay");
            } else {
                // 正常支付订单，需要支付
                prePayResVO.setPayInfo(unifiedOrderResVO.getPayInfo());
            }
            return prePayResVO;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            throw new BusinessException(BusinessErrorInfoEnum.ORDER_PAY_TIMEOUT, null, e.getMessage(), e);
        }
    }

    @Override
    public OpenRefundCreateResVO refund(OpenRefundVO refundVO) {
        return refundOrdersService.createAndSubmit(refundVO);
    }

    @Override
    public OpenVerificationResVO verification(VerificationOrderVO date) {
        // 查询待核销的账单
        final List<Bill> bills = billService.list(new LambdaQueryWrapper<Bill>().in(Bill::getSubOrderId, date.getSubOrderId()).ne(Bill::getVerificationStatus, VerificationStatusEnum.SC.getCode()));
        if (CollectionUtils.isEmpty(bills)) {
            return null;
        }
        List<Order> orders = orderMapper.selectList(new LambdaQueryWrapper<Order>().in(Order::getOrderId, bills.stream().map(Bill::getOrderId).collect(Collectors.toSet())));
        if (CollectionUtils.isEmpty(orders)) {
            return null;
        }
        Set<String> failSubOrders = new HashSet<>();
        Set<String> successSubOrders = new HashSet<>();

        final List<Bill> updateBills = new ArrayList<>();
        bills.stream().collect(Collectors.groupingBy(Bill::getOrderId)).forEach((orderId, subBills) -> {
            Order order = orders.stream().filter(o -> o.getOrderId().equals(orderId)).toList().get(0);
            if (order.getPayStatus().equals(OrderPayStatusEnum.un_pay.getCode())) {
                failSubOrders.addAll(subBills.stream().map(Bill::getSubOrderId).collect(Collectors.toSet()));
            } else {
                VerificationRequestVO verificationRequestVO = new VerificationRequestVO();
                verificationRequestVO.setUid(org.springframework.util.StringUtils.isEmpty(order.getBuyerUid()) ? order.getUid() : order.getBuyerUid());
                verificationRequestVO.setFlowId(order.getFlowId());
                verificationRequestVO.setAmount(subBills.stream().mapToInt(Bill::getTotalAmount).sum());
                verificationRequestVO.setVerificationId(orderIdHelper.getVerificationId(order.getUid()));
                verificationRequestVO.setSubFlowIds(subBills.stream().map(Bill::getSubFlowId).collect(Collectors.toSet()));
                Result<VerificationOrderResponseVO> result = paymentFeignService.verification(verificationRequestVO);
                if (!result.getRet().equals(0)) {
                    // 核销失败
                    failSubOrders.addAll(subBills.stream().map(Bill::getSubOrderId).collect(Collectors.toSet()));
                    for (Bill subBill : subBills) {
                        final Bill updateBill = new Bill();
                        updateBill.setId(subBill.getId());
                        updateBill.setVerificationStatus(VerificationStatusEnum.FL.getCode());
                        updateBill.setVerificationTime(null);
                        updateBill.setLastUpdDt(LocalDateTime.now());
                        updateBills.add(updateBill);
                    }
                } else {
                    if (CollectionUtils.isNotEmpty(result.getData().getError())) {
                        failSubOrders.addAll(subBills.stream().filter(s -> result.getData().getError().contains(s.getSubFlowId())).map(Bill::getSubOrderId).collect(Collectors.toSet()));
                        subBills.stream().filter(s -> result.getData().getError().contains(s.getSubFlowId())).forEach(subBill -> {
                            final Bill updateBill = new Bill();
                            updateBill.setId(subBill.getId());
                            updateBill.setVerificationStatus(VerificationStatusEnum.FL.getCode());
                            updateBill.setVerificationTime(null);
                            updateBill.setLastUpdDt(LocalDateTime.now());
                            updateBills.add(updateBill);
                        });
                    }
                    if (CollectionUtils.isNotEmpty(result.getData().getSuccess())) {
                        successSubOrders.addAll(subBills.stream().filter(s -> result.getData().getSuccess().contains(s.getSubFlowId())).map(Bill::getSubOrderId).collect(Collectors.toSet()));
                        subBills.stream().filter(s -> result.getData().getSuccess().contains(s.getSubFlowId())).forEach(subBill -> {
                            final Bill updateBill = new Bill();
                            updateBill.setId(subBill.getId());
                            updateBill.setVerificationId(verificationRequestVO.getVerificationId());
                            updateBill.setVerificationStatus(VerificationStatusEnum.SC.getCode());
                            updateBill.setVerificationTime(LocalDateTime.now());
                            updateBill.setLastUpdDt(LocalDateTime.now());
                            updateBills.add(updateBill);
                        });
                    }
                }
            }
        });
        if (CollectionUtils.isNotEmpty(updateBills)) {
            billService.updateBatchById(updateBills);
        }
        final OpenVerificationResVO openVerificationResVO = new OpenVerificationResVO();
        openVerificationResVO.setSuccessSubOrders(successSubOrders);
        openVerificationResVO.setFailSubOrders(failSubOrders);
        return openVerificationResVO;

    }

    /**
     * 关闭订单、修改订单金额时，需要关闭相应的流水
     *
     * @param order
     */
    private boolean closeTradeFlow(Order order) {
        AtomicBoolean isSc = new AtomicBoolean(true);
        // 如果拉起支付后，又取消，此时支付信息在缓存中，所以要先查询一下缓存，决定是否要通知支付中心关闭
        Stream.of(PaymentWayEnum.WECHAT.getCode(), PaymentWayEnum.ALIPAY.getCode(), PaymentWayEnum.UNIONPAY.getCode()).forEach(payWayCode -> {
//            TreeSet<String> orderIds = Stream.of(order.getOrderId()).collect(Collectors.toCollection(TreeSet::new));
            List<String> codeList = PaySceneEnum.getCodeList();
            codeList.add(null);
            for (String s : codeList) {
                String cacheUniqueKey = null;
                if (StringUtils.isEmpty(order.getBatchId())) {
                    cacheUniqueKey = orderIdHelper.getUniqueId(order.getUid(), order.getOrderId(), payWayCode, s);
                } else {
                    cacheUniqueKey = orderIdHelper.getUniqueIdByOrderIds(order.getUid(), null, payWayCode, s, order.getBatchId());
                }
                Optional<UnifiedOrderResVO> prePayInfo = OrderCache.getPrePayInfo(cacheUniqueKey);
                if (prePayInfo.isPresent()) {
                    String flowId = String.valueOf(prePayInfo.get().getFlowId());

                    log.info("关闭订单流水,uid:{},orderId:{},flowId:{},cacheUniqueKey:{}", order.getUid(), order.getOrderId(), flowId, cacheUniqueKey);

                    CloseOrderDTO closeOrderDTO = new CloseOrderDTO();
                    closeOrderDTO.setUid(order.getUid());
                    closeOrderDTO.setFlowId(flowId);
                    Result<String> result = paymentFeignService.closeOrder(closeOrderDTO);
                    log.info("关闭订单流水结果：{}", result);
                    if (result != null && result.getRet() != 0 && result.getErrorCode() != null && result.getErrorCode() == 1302) {
                        log.warn("关闭订单流水，该笔流水已支付成功，不允许关闭，flow_id:{}", flowId);
                        isSc.set(false);
                        continue;
                    }
                    OrderCache.delPrePayInfo(cacheUniqueKey);
                }
            }
        });
        return isSc.get();
    }

    /**
     * 订单id前缀校验
     */
    private ApplicationInfo orderIdCheck(OrderBO orderBO, List<SubOrderBO> subOrderBOS) {
        ApplicationInfo applicationInfo = this.getApplicationInfo(orderBO.getTermNo());
        BusinessErrorInfoEnum.ORDER_CREATE_ORDER_ID_ERROR.assertNotNull(applicationInfo);
        // 订单号前缀
        String idPre = applicationInfo.getIdPre();
        BusinessErrorInfoEnum.ORDER_CREATE_ORDER_ID_ERROR.assertIsTrue(orderBO.getOrderId().startsWith(idPre));
        for (SubOrderBO subOrderBO : subOrderBOS) {
            BusinessErrorInfoEnum.ORDER_CREATE_ORDER_ID_ERROR.assertIsTrue(subOrderBO.getSubOrderId().startsWith(idPre));
            BusinessErrorInfoEnum.ORDER_CREATE_ORDER_ID_ERROR.assertIsTrue(subOrderBO.getOrderId().startsWith(idPre));
        }
        // 商户有效性校验
        getPayChannelAndSetMerchant(subOrderBOS, applicationInfo);
        // 重复下单判断
        QueryWrapper<Order> conditions = new QueryWrapper<>();
        conditions.eq("order_id", orderBO.getOrderId());
        conditions.eq("uid", orderBO.getUid());
        BusinessErrorInfoEnum.ORDER_CREATE_REPEAT.assertIsTrue(orderMapper.selectCount(conditions) == 0);
        return applicationInfo;
    }

    /**
     * 商户信息校验
     *
     * @param subOrderBOS     子订单信息
     * @param applicationInfo 下单应用信息
     * @return
     * @throws BusinessException
     */
    public void getPayChannelAndSetMerchant(List<SubOrderBO> subOrderBOS, ApplicationInfo applicationInfo) throws BusinessException {
        // 调用商户中心，根据商品，确认支付渠道，并判断禁止跨渠道下单
        final QueryOrderMerchantReqVO orderMerchantReqVO = new QueryOrderMerchantReqVO();
        orderMerchantReqVO.setClientId(applicationInfo.getClientId());
        orderMerchantReqVO.setBusinessCode(applicationInfo.getBusinessCode());
        List<String> merchantCods = subOrderBOS.stream().map(SubOrderBO::getMerchantCode).collect(Collectors.toList());
        orderMerchantReqVO.setMerchantCods(merchantCods);
        orderMerchantReqVO.setOrgPaymentChannelId(applicationInfo.getOrgPaymentChannelId());
        //根据商户号获取支付渠道
        final List<QueryOrderMerchantResVO> orderMerchants = super.getOrderMerchants(orderMerchantReqVO);
        //BusinessErrorInfoEnum.SYSTEM_ERROR.assertIsTrue(CollectionUtils.isNotEmpty(orderMerchants) && orderMerchants.size() == merchantCods.size(), "商户配置异常！");
        for (SubOrderBO subOrderBO : subOrderBOS) {
            Optional<QueryOrderMerchantResVO> first = orderMerchants.stream().filter(os -> os.getMerchantCode().equals(subOrderBO.getMerchantCode())).findFirst();
            BusinessErrorInfoEnum.SYSTEM_ERROR.assertIsTrue(first.isPresent(), "商户配置异常，未查询到支付商户配置！");
            subOrderBO.setMerchantName(first.get().getMerchantName());

        }
    }

    /**
     * 组装订单推送消息
     *
     * @param order
     * @return
     */
    private PayResultOrderBO getPayResultOrderBO(Order order) {
        PayResultOrderBO orderBO = new PayResultOrderBO();
        orderBO.setOrderId(order.getOrderId());
        orderBO.setPaymentId(order.getPaymentId());
        orderBO.setFlowId(order.getFlowId());
        orderBO.setUid(order.getUid());
        orderBO.setPayTime(order.getPayTime());
        orderBO.setOrderStatus(order.getOrderStatus());
        orderBO.setPayStatus(order.getPayStatus());
        orderBO.setPayAmount(order.getPayAmount());
        orderBO.setPayScene(order.getPayScene());
        orderBO.setPayChannel(order.getPayChannel());
        orderBO.setPayWay(order.getPayWay());
        orderBO.setIsCoupon(order.getIsCoupon());
        orderBO.setDiscount(order.getDiscount());
        orderBO.setPlatformDiscount(order.getPlatformDiscount());

        List<SubOrder> subOrders = subOrderService.list(new LambdaQueryWrapper<SubOrder>().eq(SubOrder::getOrderId, order.getOrderId()));
        List<PayResultSubOrderBO> subOrderBOS = subOrders.stream().map(s -> {
            PayResultSubOrderBO ps = new PayResultSubOrderBO();
            ps.setOrderId(s.getOrderId());
            ps.setSubOrderId(s.getSubOrderId());
            ps.setSubFlowId(s.getSubFlowId());
            ps.setMerchantCode(s.getMerchantCode());
            ps.setMerchantName(s.getMerchantName());
            ps.setSubOrderAmount(s.getSubOrderAmount());
            ps.setPayAmount(s.getPayAmount());
            ps.setIsCoupon(s.getIsCoupon());
            ps.setDiscount(s.getDiscount());
            return ps;
        }).toList();
        orderBO.setSubOrders(subOrderBOS);
        return orderBO;
    }

}
